using System;


namespace Axe.Geometry
{
	/// <summary>
	/// Summary description for OOBB.
	/// </summary>
	public class AxisOrientedBox : AxisAlignedBox, IOrientedObject
	{
		Vector3 mOrientation = new Vector3();
		Matrix3 mWorld2Object = new Matrix3();
		Matrix3 mObject2World = new Matrix3();

		public Plane3[]  Planes = new Plane3[6];
		public Vector3[] Anchors = new Vector3[8];

		protected void ComputePlanes()
		{
			
			Planes[0] = Plane3.FromCoplanarPoints(Anchors[1],Anchors[3],Anchors[2]);
			Planes[1] = Plane3.FromCoplanarPoints(Anchors[4],Anchors[6],Anchors[7]);
			Planes[2] = Plane3.FromCoplanarPoints(Anchors[2],Anchors[6],Anchors[4]);
			Planes[3] = Plane3.FromCoplanarPoints(Anchors[3],Anchors[7],Anchors[6]);
			Planes[4] = Plane3.FromCoplanarPoints(Anchors[1],Anchors[5],Anchors[7]);
			Planes[5] = Plane3.FromCoplanarPoints(Anchors[4],Anchors[5],Anchors[1]);

			//	for(int i=0;i<6;i++)
			//	Planes[i].Flip();
			//*/
			/*
			Planes[0] = Plane3.FromCoplanarPoints(Anchors[2],Anchors[3],Anchors[1]);
			Planes[1] = Plane3.FromCoplanarPoints(Anchors[7],Anchors[6],Anchors[4]);
			Planes[2] = Plane3.FromCoplanarPoints(Anchors[4],Anchors[6],Anchors[2]);
			Planes[3] = Plane3.FromCoplanarPoints(Anchors[6],Anchors[7],Anchors[3]);
			Planes[4] = Plane3.FromCoplanarPoints(Anchors[7],Anchors[5],Anchors[1]);
			Planes[5] = Plane3.FromCoplanarPoints(Anchors[1],Anchors[5],Anchors[4]);
			*/

		}

		protected void IdentifyAnchors()
		{
			int index = 0;
			for(int x=0;x<2;x++)
			{
				for(int y=0;y<2;y++)
				{
					for(int z=0;z<2;z++)
					{
						//Anchors[index++].Set(X[x] + mCenter.X,Y[y] + mCenter.Y,Z[z] + mCenter.Z);
						Anchors[index++].Set(X[x],Y[y],Z[z]);
					}
				}
			}
		}


		public AxisOrientedBox(Vector3 center,Vector3 size) : base(center,size)
		{
			for(int i=0;i<8;i++)
				Anchors[i] = new Vector3();
			for(int i=0;i<6;i++)
				Planes[i] = new Plane3(Vector3.Zero,0);
			UpdateCoords();
		}		

		public void UpdateCoords()
		{
			UpdateXYZ();
			IdentifyAnchors();
			CalculateMatrixes();
			for(int i=0;i<8;i++)
			{
				Anchors[i] = mObject2World * Anchors[i];
				Anchors[i].Add(mCenter);
			}
			ComputePlanes();
		}

		public bool PointIn(Vector3 v)
		{
			for(int i=0;i<6;i++)
			{
				Sign s = Planes[i].GetSign(v);
				if(	s == Sign.Positive)
					return false;
			}
			return true;
			/*
			Vector3 trans = World2Object * v;
			//Vector3 trans = Object2World * v;

			if(X[0] < v.X && X[1] > v.X && Y[0] < v.Y && Y[1] > v.Y && Z[0] < v.Z && Z[1] > v.Z)
			return true;
			return false;
			*/
		}

		public bool GetLineIntersection(Vector3 p1,Vector3 p2,ref Vector3 exact,ref Vector3 normal)
		{
			for(int i=0;i<6;i++)
			{
				if(	Planes[i].IsIntersection(p1,p2) )
				{
					exact.Set(Planes[i].GetIntersection(p1,p2));
					normal.Set(Planes[i].Normal);
					return true;
				}
			}
			return false;
		}

		public void GetLineIntersections(Vector3 p1,Vector3 p2,ref Vector3[] exact,ref Vector3[] normal)
		{
			for(int i=0;i<6;i++)
			{
				if(	Planes[i].IsIntersection(p1,p2) )
				{
					exact[i] = Planes[i].GetIntersection(p1,p2);
					normal[i] = new Vector3(Planes[i].Normal);
				}
				else
				{
					exact[i] = null;
					normal[i] = null;
				}
			}
		}

		#region IOrientedObject Members

		public Vector3 Orientation
		{
			get
			{
				return mOrientation;
			}
			set
			{
				mOrientation.Set(value);
			}
		}

		public Matrix3 World2ObjectMatrix
		{
			get
			{
				return mWorld2Object;
			}
		}

		public Matrix3 Object2WorldMatrix
		{
			get
			{
				return mObject2World;
			}
		}

		public void CalculateMatrixes()
		{
			Matrix3 xRot = Matrix3.FromRotation(Vector3.XAxis,Math3D.ToRadians(Orientation.X));
			Matrix3 yRot = Matrix3.FromRotation(Vector3.YAxis,Math3D.ToRadians(Orientation.Y));
			Matrix3 zRot = Matrix3.FromRotation(Vector3.ZAxis,Math3D.ToRadians(Orientation.Z));
			mObject2World = (xRot * yRot * zRot);// * mMov;
			
			xRot = Matrix3.FromRotation(Vector3.XAxis,Math3D.ToRadians(-Orientation.X));
			yRot = Matrix3.FromRotation(Vector3.YAxis,Math3D.ToRadians(-Orientation.Y));
			zRot = Matrix3.FromRotation(Vector3.ZAxis,Math3D.ToRadians(-Orientation.Z));
			mWorld2Object = (xRot * yRot * zRot);// * mMov;
			
		}

		public void ResetOrientation()
		{
			mOrientation.Set(0,0,0);
			mObject2World.SetToIdentity();
			mWorld2Object.SetToIdentity();
			UpdateCoords();
		}

		public Vector3 ToWorldCoordinateSystem(Vector3 v)
		{
			Vector3 vect = new Vector3(v);
			return mObject2World * vect;
		}

		public Vector3 ToObjectCoordinateSystem(Vector3 v)
		{
			Vector3 vect = new Vector3(v);
			return  mWorld2Object * vect;
		}
		#endregion
	}
}
